import { CreepRoles, SpawnTask } from '@/modules/structures/spawn/types'
import { getFreeSpace } from '@/utils/position'
import { SourceInfo, HarvesterData } from './types'
import { isInterval, isRoomInterval } from '@/ayaka'
import { BodyPartArrayType } from '@/utils/common'
import { createHarvesterBody, harvesterWork } from './harvester'
import SpawnController, { getCreeps } from '@/modules/structures/spawn'
import TransportTaskManager from '../transport'
import { RoomSafeState } from '@/room/state/types'
import StructureCache from '@/modules/structureCache'

/**
 * 挖矿任务管理器
 */
export default class HarvestTaskManager {
    /**
     * 不可实例化
     */
    protected constructor() {
        throw new Error('HarvestTaskManager 不可被实例化！')
    }

    /**
     * 获取 memory
     */
    public static getMemory(room: Room) {
        if (!room.memory.source) {
            const sources = room.find(FIND_SOURCES)
            room.memory.source = {}
            sources.forEach((source) => {
                room.memory.source[source.id] = {
                    harvester: [],
                    freePos: getFreeSpace(source.pos).length,
                }
            })
        }
        // 重置 danger 标志
        if (Game.time % 6300 === 0 && room.memory.state.safe?.state === RoomSafeState.normal) {
            for (const sourceInfo of Object.values(room.memory.source)) {
                delete sourceInfo.isDanger
            }
        }
        return room.memory.source
    }

    /**
     * 孵化 harvester 并执行挖矿任务
     */
    public static run(room: MyRoom) {
        const memory = HarvestTaskManager.getMemory(room)
        for (const sourceId in memory) {
            const sourceInfo = memory[sourceId as Id<Source>]
            // 已经存在的 harvester
            const harvesters = HarvestTaskManager.getHarvester(room, sourceInfo)

            HarvestTaskManager.initHarvesterMemory(harvesters)
            HarvestTaskManager.spawnHarvester(room, sourceInfo, harvesters)

            // harvester 工作
            harvesterWork(harvesters, sourceId as Id<Source>, sourceInfo)
            // 发布能量搬运任务
            HarvestTaskManager.addTransportTask(room, sourceInfo.containerId, sourceInfo)
        }
    }

    /**
     * 判断能否并孵化新的 harvester
     */
    protected static spawnHarvester(room: Room, sourceInfo: SourceInfo, creeps: Creep[]) {
        if (!isRoomInterval(room, 27)) return

        if (room.memory.state.safe?.state !== RoomSafeState.normal && sourceInfo.isDanger) return

        // 如果已经有 harvester 的孵化任务了就等等
        if (SpawnController.searchSpawnTaskByRole(room, CreepRoles.harvester).length) return

        // 矿工无缝对接的关键！
        creeps = creeps.filter((creep) => {
            // 没有 spawning 就一定有 ticksToLive
            return (
                creep.spawning ||
                creep.ticksToLive! > Math.max(creep.memory.travelTime || 0, 10) + creep.body.length * 2
            )
        })

        // 空闲点位满了
        if (creeps.length >= sourceInfo.freePos) return

        // 800能量之前要求总 work 数大于等于6，之后只出一个爬
        if (room.energyCapacityAvailable < 800) {
            const workCount = creeps.reduce((count, creep) => count + (creep.memory.bodyParts?.[WORK] || 0), 0)
            if (workCount >= 6) return
        } else if (creeps.length > 0) return

        HarvestTaskManager.addHarvesterSpawnTask(room, sourceInfo, createHarvesterBody(room))
    }

    /**
     * 初始化 harvester memory
     */
    protected static initHarvesterMemory(creeps: Creep[]) {
        creeps.forEach((creep) => {
            if (!creep.memory.bodyParts) {
                creep.memory.bodyParts = {
                    [WORK]: creep.getActiveBodyparts(WORK),
                }
            }
            if (!creep.memory.data) {
                creep.memory.data = {
                    aroundStructIds: undefined,
                } as HarvesterData
            }
        })
    }

    /**
     * 获取 harvester，同时清除过期爬
     */
    protected static getHarvester(room: Room, sourceInfo: SourceInfo) {
        // const harvesters: Creep[] = []
        // sourceInfo.harvester.forEach((creepName) => {
        //     const creep = Game.creeps[creepName]
        //     if (!creep && !SpawnController.searchSpawnTaskByCreepName(room, creepName)) {
        //         sourceInfo.harvester = sourceInfo.harvester.filter((name) => name !== creepName)
        //     }
        //     if (creep) {
        //         harvesters.push(creep)
        //     }
        // })
        // return harvesters

        return getCreeps(room, sourceInfo.harvester)
    }

    /**
     * 添加 harvester 的孵化任务
     */
    protected static addHarvesterSpawnTask(room: Room, sourceInfo: SourceInfo, body: BodyPartArrayType) {
        const task: SpawnTask = {
            role: CreepRoles.harvester,
            body,
            defaultAdaption: true,
        }
        const creepName = SpawnController.addSpawnTask(room, task)
        if (!creepName) return

        sourceInfo.harvester.push(creepName)
    }

    /**
     * 发布能量搬运任务
     */
    protected static addTransportTask(
        room: MyRoom,
        containerId: Id<StructureContainer> | undefined,
        sourceInfo: SourceInfo,
    ) {
        if (!containerId || !isInterval(11)) return

        const container = Game.getObjectById(containerId)
        if (!container) return

        if (container.store['energy'] < 700) return
        else if (container.store['energy'] < 1400) {
            const tasks = TransportTaskManager.searchTransportTaskByName(room, `${container.id}`)
            if (tasks.length >= 1) return
        } else {
            const tasks = TransportTaskManager.searchTransportTaskByName(room, `${container.id}`)
            if (tasks.length >= 2) return
        }

        let target: StructureStorage | StructureTerminal | StructureContainer | undefined = undefined
        if (room.storage && room.storage.store.getFreeCapacity() > 50000) {
            target = room.storage
        } else if (room.terminal && room.terminal.store.getFreeCapacity() > 50000) {
            target = room.terminal
        } else {
            // const upgradeMemory = UpgradeTaskManager.getMemory(room)
            // if (upgradeMemory.containerIds?.length) {
            //     const containers = upgradeMemory.containerIds
            //         .map(Game.getObjectById)
            //         .filter(Boolean) as StructureContainer[]
            //     target = containers.find((container) => container.store.getFreeCapacity() > 500)
            // }
        }

        if (!target) return

        TransportTaskManager.addOneToOneTransportTask(
            room,
            `${container.id}`,
            {
                sourceId: container.id,
                targetId: target.id,
                resInfo: {
                    energy: {
                        require: 1e7,
                        has: 0,
                    },
                },
            },
            6,
            undefined,
            sourceInfo.isDanger,
        )
    }

    /**
     * 注册 container
     */
    public static registerContainer(room: Room, containers: StructureContainer[]): StructureContainer[] {
        const memory = HarvestTaskManager.getMemory(room)
        const sources = Object.keys(memory).map(Game.getObjectById) as Source[]
        // source 占用的 container
        const sourceContainerIds = [] as Id<StructureContainer>[]
        sources.forEach((source) => {
            const container = source.pos.findInRange(containers, 1)[0]
            if (container) {
                memory[source.id].containerId = container.id
                sourceContainerIds.push(container.id)
            }
        })
        return containers.filter((container) => !sourceContainerIds.includes(container.id))
    }

    /**
     * 注册 link
     */
    public static registerLink(room: Room, links: StructureLink[]) {
        const memory = HarvestTaskManager.getMemory(room)
        const sources = Object.keys(memory).map(Game.getObjectById) as Source[]
        // source 占用的 link
        const sourceLinkIds = [] as Id<StructureLink>[]
        sources.forEach((source) => {
            const link = source.pos.findInRange(links, 2)[0]
            if (link) {
                const sourceInfo = memory[source.id]
                sourceInfo.linkId = link.id
                sourceLinkIds.push(link.id)
                if (room.memory.centerLinkId && sourceInfo.containerId) {
                    StructureCache.remove(sourceInfo.containerId)
                    delete sourceInfo.containerId
                }
            }
        })
        return links.filter((link) => !sourceLinkIds.includes(link.id))
    }
}
